package com.onesports.intelligent.k12.polarlight.service.sys;

import static com.onesports.intelligent.k12.polarlight.common.constant.Constants.NOT_PUT_GREY;
import static com.onesports.intelligent.k12.polarlight.common.constant.Constants.PUT_GREY;
import static com.onesports.intelligent.k12.polarlight.common.utils.DateUtils.HH_MM;
import static com.onesports.intelligent.k12.polarlight.common.utils.DateUtils.YYYY_MM_DD;

import cn.oneframework.common.domain.dto.IdDTO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.onesports.framework.kit.common.util.BeanUtils;
import com.onesports.framework.kit.common.util.ParamUtils;
import com.onesports.framework.kit.common.util.TimeUtils;
import com.onesports.intelligent.k12.polarlight.common.domain.entity.BaseEntity;
import com.onesports.intelligent.k12.polarlight.common.errors.exceptions.BusinessException;
import com.onesports.intelligent.k12.polarlight.constant.CodeConstants;
import com.onesports.intelligent.k12.polarlight.domain.dto.market.ProductCourseDetailsDTO;
import com.onesports.intelligent.k12.polarlight.domain.dto.market.ProductInsertDTO;
import com.onesports.intelligent.k12.polarlight.domain.dto.market.ProductIsSellDTO;
import com.onesports.intelligent.k12.polarlight.domain.dto.market.ProductSelectDTO;
import com.onesports.intelligent.k12.polarlight.domain.dto.operation.OperationProductCourseDTO;
import com.onesports.intelligent.k12.polarlight.domain.dto.organization.CampusIdDTO;
import com.onesports.intelligent.k12.polarlight.domain.entity.course.ClassInfo;
import com.onesports.intelligent.k12.polarlight.domain.entity.course.Course;
import com.onesports.intelligent.k12.polarlight.domain.entity.course.CourseGuidePriceRel;
import com.onesports.intelligent.k12.polarlight.domain.entity.course.CourseSchedule;
import com.onesports.intelligent.k12.polarlight.domain.entity.course.CourseScheduleDetail;
import com.onesports.intelligent.k12.polarlight.domain.entity.course.CourseScheduleDetailCoachRel;
import com.onesports.intelligent.k12.polarlight.domain.entity.course.CourseSellPriceRel;
import com.onesports.intelligent.k12.polarlight.domain.entity.course.SpellingClassPeriod;
import com.onesports.intelligent.k12.polarlight.domain.entity.market.Orders;
import com.onesports.intelligent.k12.polarlight.domain.entity.market.Product;
import com.onesports.intelligent.k12.polarlight.domain.entity.market.ProductCampusRel;
import com.onesports.intelligent.k12.polarlight.domain.entity.market.ProductImageRel;
import com.onesports.intelligent.k12.polarlight.domain.entity.market.ProductSellPriceRel;
import com.onesports.intelligent.k12.polarlight.domain.vo.course.CourseIdAndCourseNamelVO;
import com.onesports.intelligent.k12.polarlight.domain.vo.course.CourseScheduleDetailVO;
import com.onesports.intelligent.k12.polarlight.domain.vo.course.GetCampusIntroduceVO;
import com.onesports.intelligent.k12.polarlight.domain.vo.course.GetCourseVO;
import com.onesports.intelligent.k12.polarlight.domain.vo.course.MyCourseScheduleVO;
import com.onesports.intelligent.k12.polarlight.domain.vo.course.MySpellClassVO;
import com.onesports.intelligent.k12.polarlight.domain.vo.course.PeriodVO;
import com.onesports.intelligent.k12.polarlight.domain.vo.course.ProductSpellClassVO;
import com.onesports.intelligent.k12.polarlight.domain.vo.course.SpellClassPriceVO;
import com.onesports.intelligent.k12.polarlight.domain.vo.course.SpellTypeVO;
import com.onesports.intelligent.k12.polarlight.domain.vo.product.ProductCourseDetailsVO;
import com.onesports.intelligent.k12.polarlight.domain.vo.product.ProductCourseVO;
import com.onesports.intelligent.k12.polarlight.domain.vo.product.ProductMinPriceVO;
import com.onesports.intelligent.k12.polarlight.domain.vo.product.ProductSelectByIdVO;
import com.onesports.intelligent.k12.polarlight.domain.vo.product.ProductSelectPageVO;
import com.onesports.intelligent.k12.polarlight.domain.vo.product.WxEvaluateVO;
import com.onesports.intelligent.k12.polarlight.domain.vo.product.WxProductVO;
import com.onesports.intelligent.k12.polarlight.enums.ClassInfoStatusEnum;
import com.onesports.intelligent.k12.polarlight.enums.OrderStatusEnum;
import com.onesports.intelligent.k12.polarlight.mapper.course.ClassInfoMapper;
import com.onesports.intelligent.k12.polarlight.mapper.course.CourseGuidePriceRelMapper;
import com.onesports.intelligent.k12.polarlight.mapper.course.CourseMapper;
import com.onesports.intelligent.k12.polarlight.mapper.course.CourseScheduleDetailMapper;
import com.onesports.intelligent.k12.polarlight.mapper.course.CourseScheduleMapper;
import com.onesports.intelligent.k12.polarlight.mapper.course.CourseSellPriceRelMapper;
import com.onesports.intelligent.k12.polarlight.mapper.course.ScheduleDetailCoachRelMapper;
import com.onesports.intelligent.k12.polarlight.mapper.market.OrdersMapper;
import com.onesports.intelligent.k12.polarlight.mapper.market.ProductCampusRelMapper;
import com.onesports.intelligent.k12.polarlight.mapper.market.ProductImageRelMapper;
import com.onesports.intelligent.k12.polarlight.mapper.market.ProductMapper;
import com.onesports.intelligent.k12.polarlight.mapper.market.ProductSellPriceRelMapper;
import com.onesports.intelligent.k12.polarlight.mapper.organization.OrganizationCampusMapper;
import com.onesports.intelligent.k12.polarlight.mapper.organization.OrganizationMapper;
import com.onesports.intelligent.k12.polarlight.security.SecurityUtils;
import com.onesports.intelligent.k12.polarlight.service.course.CourseScheduleService;
import com.onesports.intelligent.k12.polarlight.service.course.SpellingClassPeriodService;
import com.onesports.intelligent.k12.polarlight.util.BeanCopyUtil;
import com.onesports.intelligent.k12.polarlight.util.CodeUtils;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.TreeSet;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * 班级
 *
 * @author wusy
 * @since 1.0.0 2022-03-16
 */
@Service
@RequiredArgsConstructor
public class ProductService extends ServiceImpl<ProductMapper, Product> {

    private static final Logger log = LoggerFactory.getLogger(ProductService.class);


    private final ProductMapper productMapper;
    private final ProductImageRelMapper productImageRelMapper;
    private final ProductSellPriceRelMapper productSellPriceRelMapper;
    private final ProductCampusRelMapper productCampusRelMapper;
    private final OrdersMapper ordersMapper;
    private final ClassInfoMapper classInfoMapper;
    private final OrganizationMapper organizationMapper;
    private final CourseSellPriceRelMapper courseSellPriceRelMapper;
    private final CourseGuidePriceRelMapper courseGuidePriceRelMapper;
    private final CourseMapper courseMapper;
    private final OrganizationCampusMapper organizationCampusMapper;
    private final CourseScheduleMapper courseScheduleMapper;
    private final CourseScheduleDetailMapper courseScheduleDetailMapper;
    private final ScheduleDetailCoachRelMapper scheduleDetailCoachRelMapper;
    private final CourseScheduleService courseScheduleService;
    private final CodeUtils codeUtils;
    private final SpellingClassPeriodService spellingClassPeriodService;


    /**
     * 添加商品信息
     *
     * @param productInsertDTO
     */
    @Transactional(rollbackFor = Exception.class)
    public void add(ProductInsertDTO productInsertDTO) {
        //与商品表所关联的表-product  -product_image_rel  -product_sell_price_rel -product_campus_rel
        //新建商品实体类 dto将信息注入

        Product product = new Product();
        BeanUtils.copyProperties(productInsertDTO, product);
        //获取机构流水码
        String organizationCode = organizationMapper.selectById(productInsertDTO.getOrganizationId()).getOrganizationCode();
        String productCode = "SP" + organizationCode.trim() + codeUtils.autoSerialNumberNoPrefix(CodeConstants.PRODUCT_CODE, 4);
        product.setProductCode(productCode);
        //实体加入商品表
        productMapper.insert(product);
        String productId = product.getId();
        //新建主图关联表 dto将信息注入 并取出商品id注入
        ProductImageRel productImageRel = new ProductImageRel();
        productImageRel.setImageUrl(productInsertDTO.getMainImage());
        productImageRel.setProductId(productId);
        //实体加入主图表
        productImageRelMapper.insert(productImageRel);
        //新建拼班类型表

        List<CourseSchedule> courseSchedules =courseScheduleMapper.selectList(new QueryWrapper<CourseSchedule>().lambda()
                .eq(CourseSchedule::getCourseId, productInsertDTO.getCourseId())
                .eq(CourseSchedule::getOrganizationId,productInsertDTO.getOrganizationId()));

        if(CollectionUtils.isNotEmpty(courseSchedules)){
            List<String> collect = courseSchedules.stream()
                    .map(CourseSchedule::getCampusId)
                    .distinct()
                    .collect(Collectors.toList());
            collect.forEach(c -> {
                ProductCampusRel productCampusRel = new ProductCampusRel();
                //添加校区信息后将实体加入校区关联表
                productCampusRel.setCampusId(c);
                productCampusRel.setProductId(productId);
                productCampusRel.setOrganizationId(productInsertDTO.getOrganizationId());
                productCampusRelMapper.insert(productCampusRel);
                List<CourseSellPriceRel> courseSellPriceRels = courseSellPriceRelMapper.selectList(new QueryWrapper<CourseSellPriceRel>().lambda()
                        .eq(CourseSellPriceRel::getCourseId, productInsertDTO.getCourseId())
                        .eq(CourseSellPriceRel::getCampusId, c));
                courseSellPriceRels.forEach(courseSellPriceRel -> {
                    CourseGuidePriceRel courseGuidePriceRel = courseGuidePriceRelMapper.selectById(courseSellPriceRel.getGuidePriceId());
                    if(courseGuidePriceRel==null){
                        return;
                    }
                    ProductSellPriceRel productSellPriceRel = new ProductSellPriceRel();
                    productSellPriceRel.setProductId(productId);
                    productSellPriceRel.setCourseSellPriceRelId(courseSellPriceRel.getId());
                    productSellPriceRel.setTypeName(courseGuidePriceRel.getTypeName());
                    productSellPriceRel.setMinNum(courseGuidePriceRel.getMinNum());
                    productSellPriceRel.setMaxNum(courseGuidePriceRel.getMaxNum());
                    productSellPriceRel.setPrice(courseSellPriceRel.getPrice());
                    productSellPriceRel.setProductCampusId(productCampusRel.getId());
                    //实体加入拼班表
                    productSellPriceRelMapper.insert(productSellPriceRel);
                });
            });
        }
        if(productInsertDTO.getSell()){
            List<CourseSchedule> courseSchedules1 = courseScheduleMapper.selectList(new QueryWrapper<CourseSchedule>().lambda()
                    .eq(CourseSchedule::getCourseId, productInsertDTO.getCourseId())
                    .eq(CourseSchedule::getOrganizationId, SecurityUtils.getOrganizationId())
                    .eq(CourseSchedule::getPublishStatus, true)
                    .ge(CourseSchedule::getEndDate, new Date()));
            if(CollectionUtils.isEmpty(courseSchedules1)){
                throw new BusinessException("课表未发布无法上架");
            }
            productMapper.updateSell(productInsertDTO.getId());
        }
    }

    /**
     * 查询课程信息
     */
    public List<GetCourseVO> getCourse() {
        List<String> collect = productMapper.selectList(new QueryWrapper<Product>().lambda()
                        .eq(Product::getOrganizationId,SecurityUtils.getOrganizationId()))
                .stream()
                .map(Product::getCourseId)
                .collect(Collectors.toList());
        if (collect.size() < 1) {
            List<Course> courses = courseMapper.selectList(null);
            return BeanCopyUtil.copyListProperties(courses, GetCourseVO::new);
        }
        List<Course> courses = courseMapper.selectList(new QueryWrapper<Course>().lambda().notIn(Course::getId, collect));
        return BeanCopyUtil.copyListProperties(courses, GetCourseVO::new);
    }

    /**
     * 课程介绍
     */
    public GetCampusIntroduceVO getCampus(String courseId, String organizationId) {
        //获取课程介绍
        String courseDetail = courseMapper.selectById(courseId).getCourseDetail();
        GetCampusIntroduceVO getCampusIntroduceVO = new GetCampusIntroduceVO();

        getCampusIntroduceVO.setCourseIntroduce(courseDetail);
        return getCampusIntroduceVO;
    }

    /**
     * 获取商品课程列表
     *
     * @param dto dto
     * @return {@link List}<{@link ProductCourseVO}>
     */
    public List<ProductCourseVO> getProductCourseList(CampusIdDTO dto) {
        // 根据校区Id查询商品课程列表
        List<ProductCourseVO> list = productMapper.getProductCourseList(dto);
        // 查询所有已付款订单
        LambdaQueryWrapper<Orders> orderWrapper = new LambdaQueryWrapper<>();
        // 2已付款
        orderWrapper.eq(Orders::getOrderStatus, OrderStatusEnum.ALREADY.getValue());
        orderWrapper.eq(Orders::getCampusId, dto.getCampusId());
        orderWrapper.eq(Orders::getDeleted, Boolean.FALSE);
        List<Orders> orderList = ordersMapper.selectList(orderWrapper);
        // 根据商品Id分组
        Map<String, List<Orders>> ordersMap = orderList.stream().collect(Collectors.groupingBy(Orders::getProductId));
        // 查询已拼班班级
        LambdaQueryWrapper<ClassInfo> classWrapper = new LambdaQueryWrapper<>();
        classWrapper.eq(ClassInfo::getClassStatus, ClassInfoStatusEnum.FINISH_CLASS.getValue());
        classWrapper.eq(ClassInfo::getCampusId, dto.getCampusId());
        classWrapper.eq(ClassInfo::getDeleted, Boolean.FALSE);
        List<ClassInfo> classInfos = classInfoMapper.selectList(classWrapper);
        // 根据商品Id分组
        Map<String, List<ClassInfo>> classInfoMap = classInfos.stream().collect(Collectors.groupingBy(ClassInfo::getProductId));
        // 查询商品最低价格
        List<ProductMinPriceVO> productMinPriceList = productSellPriceRelMapper.findProductMinPrice();
        Map<String, ProductMinPriceVO> productMinPriceMap = productMinPriceList.stream().collect(Collectors.toMap(ProductMinPriceVO::getProductId, pm -> pm));
        for (ProductCourseVO productCourseVO : list) {
            List<Orders> orders = ordersMap.get(productCourseVO.getProductId());
            productCourseVO.setPaymentNumber(ParamUtils.isNotEmpty(orders) ? orders.size() : 0);
            List<ClassInfo> classList = classInfoMap.get(productCourseVO.getProductId());
            productCourseVO.setSpellingClassNumber(ParamUtils.isNotEmpty(classList) ? classList.size() : 0);
            ProductMinPriceVO productMinPriceVO = productMinPriceMap.get(productCourseVO.getProductId());
            productCourseVO.setPrice(ParamUtils.isNotEmpty(productMinPriceVO) ? productMinPriceVO.getPrice() : BigDecimal.ZERO);
        }
        return list;
    }

    /**
     * 商品详情
     *
     * @param dto dto
     * @return {@link List}<{@link ProductCourseDetailsVO}>
     */
    public ProductCourseDetailsVO getCourseDetails(ProductCourseDetailsDTO dto) {

        //查询商品信息
        ProductCourseDetailsVO pcd = productMapper.getCourseDetails(dto);
        Date date = new Date();
        Date currentDate = TimeUtils.toDate(TimeUtils.toText(date, TimeUtils.DATE_FORMAT), TimeUtils.DATE_FORMAT);
        // 查询商品最低价格
        LambdaQueryWrapper<ProductCampusRel> pcWrap = new LambdaQueryWrapper<>();
        pcWrap.eq(ProductCampusRel::getProductId,dto.getProductId());
        pcWrap.eq(ProductCampusRel::getCampusId,dto.getCampusId());
        ProductCampusRel productCampusRel = productCampusRelMapper.selectOne(pcWrap);
        //根据商品Id和校区关联商品的主键id查询商品拼班类型表
        LambdaQueryWrapper<ProductSellPriceRel> pspWrap = new LambdaQueryWrapper<>();
        pspWrap.eq(ProductSellPriceRel:: getProductId,dto.getProductId());
        pspWrap.eq(ProductSellPriceRel:: getProductCampusId,productCampusRel.getId());
        List<ProductSellPriceRel> productSellPriceRelList = productSellPriceRelMapper.selectList(pspWrap);
        BigDecimal min = productSellPriceRelList.stream().map(ProductSellPriceRel::getPrice)
            .min(Comparator.naturalOrder()).orElse(BigDecimal.ZERO);
        log.info("最小值:"+min);
        pcd.setPrice(min);
        //ProductMinPriceVO productMinPriceVO = productSellPriceRelMapper.queryProductMinPrice(dto.getProductId());
        //pcd.setPrice(ParamUtils.isNotEmpty(productMinPriceVO) ? productMinPriceVO.getPrice() : BigDecimal.ZERO);
        //最多n人团
        ProductMinPriceVO pmpVo = productSellPriceRelMapper.queryProductMaxNum(dto.getProductId());
        pcd.setMaxNum(ParamUtils.isNotEmpty(pmpVo) ? pmpVo.getMaxNum() : 0);
        //根据商品Id和校区Id查询商品列表(班级状态为: 0,1,3) 并判断当前时间小等于结束时间(sql已判断)
        List<ProductSpellClassVO> productSpellClassList = classInfoMapper.getProductSpellClass(dto);
        List<ProductSpellClassVO> pscList = Lists.newArrayList();
        if (ParamUtils.isNotEmpty(productSpellClassList)) {
            //判断是否满足最高人数限制,满足则过滤掉
            pscList = productSpellClassList.stream().filter(psc -> psc.getUseStudentNum().compareTo(psc.getMaxNum()) < 0).collect(Collectors.toList());
        }
        if(ParamUtils.isNotEmpty(pscList)){
            for (ProductSpellClassVO productSpellClassVO : pscList) {
                SpellingClassPeriod earliestPeriod = this.spellingClassPeriodService.getEarliestCurrentPeriod(productSpellClassVO.getClassInfoId(), currentDate);
                if(ParamUtils.isEmpty(earliestPeriod)){
                    pscList = pscList.stream().filter(nsc-> !nsc.getClassInfoId().equals(productSpellClassVO.getClassInfoId()) ).collect(Collectors.toList());
                }

            }

        }

        pcd.setProductSpellClassList(pscList);
        return pcd;
    }

    /**
     * 带分页的条件查询
     * 这块少了个机构id  后续记得补
     *
     * @return
     */
    public IPage<ProductSelectPageVO> selectPage(ProductSelectDTO productSelectDTO) {
        IPage<ProductSelectPageVO> page = productMapper.findPage(new Page<ProductSelectPageVO>(productSelectDTO.getPage(), productSelectDTO.getRow()),
                productSelectDTO);
        return page;
    }

    /**
     * 根据id查询商品详情
     *
     * @param productId
     * @return
     */
    public ProductSelectByIdVO selectById(String productId) {
        //新建视图对象
        ProductSelectByIdVO productSelectByIdVO = new ProductSelectByIdVO();
        //根据id查出商品信息,相关信息存入vo
        Product product = productMapper.selectById(productId);
        BeanUtils.copyProperties(product, productSelectByIdVO);
        //将商品主图信息插入
        ProductImageRel productImageRel = productImageRelMapper.selectList(new QueryWrapper<ProductImageRel>().lambda()
                        .eq(ProductImageRel::getProductId, productId)).stream()
                .findFirst()
                .orElse(new ProductImageRel());
        String imageUrl = productImageRel.getImageUrl();

        productSelectByIdVO.setMainImage(imageUrl);
        //对课程实体进行判空
        Course course = Optional.ofNullable(courseMapper.selectById(product.getCourseId())).orElse(new Course());
        //将关联课程名称插入
        productSelectByIdVO.setCourseName(course.getCourseName());
        productSelectByIdVO.setCourseId(course.getId());
        return productSelectByIdVO;
    }

    /**
     * 根据id修改商品信息
     *
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public void update(ProductInsertDTO productInsertDTO) {
        //与商品表所关联的表-product  -product_image_rel  -product_sell_price_rel -product_campus_rel
        //新建商品实体类 dto将信息注入
        Product product = new Product();
        BeanUtils.copyProperties(productInsertDTO, product);
        //实体修改入商品表
        productMapper.updateById(product);
        //新建主图关联表 dto将信息注入 并取出商品id注入
        ProductImageRel productImageRel = new ProductImageRel();
        productImageRel.setImageUrl(productInsertDTO.getMainImage());
        ProductImageRel productImageRel1 = productImageRelMapper.selectList(new QueryWrapper<ProductImageRel>().lambda()
                .eq(ProductImageRel::getProductId, productInsertDTO.getId())).stream().findFirst().orElse(new ProductImageRel());
        productImageRel.setId(productImageRel1.getId());
        //实体修改入主图表
        productImageRelMapper.updateById(productImageRel);
        if(productInsertDTO.getSell()){
            List<CourseSchedule> courseSchedules = courseScheduleMapper.selectList(new QueryWrapper<CourseSchedule>().lambda()
                    .eq(CourseSchedule::getCourseId, productInsertDTO.getCourseId())
                    .eq(CourseSchedule::getOrganizationId, SecurityUtils.getOrganizationId())
                    .eq(CourseSchedule::getPublishStatus, true)
                    .ge(CourseSchedule::getEndDate, new Date()));
            if(CollectionUtils.isEmpty(courseSchedules)){
                throw new BusinessException("课表未发布无法上架");
            }
            productMapper.updateSell(productInsertDTO.getId());
        }
    }

    /**
     * 修改上下架状态
     *
     * @param productIsSellDTO
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public void selectIsSell(ProductIsSellDTO productIsSellDTO) {
        Product product = new Product();
        BeanUtils.copyProperties(productIsSellDTO, product);

        if(productIsSellDTO.getSell()){
            String courseId = productMapper.selectList(new QueryWrapper<Product>().lambda()
                    .eq(Product::getId, productIsSellDTO.getId())).stream()
                    .findFirst().orElse(new Product()).getCourseId();
            List<CourseSchedule> courseSchedules = courseScheduleMapper.selectList(new QueryWrapper<CourseSchedule>().lambda()
                    .eq(CourseSchedule::getCourseId, courseId)
                    .eq(CourseSchedule::getOrganizationId, SecurityUtils.getOrganizationId())
                    .eq(CourseSchedule::getPublishStatus, true)
                    .ge(CourseSchedule::getEndDate, new Date()));
            if(CollectionUtils.isEmpty(courseSchedules)){
                throw new BusinessException("课表未发布无法上架");
            }
            productMapper.updateSell(productIsSellDTO.getId());
        }else{
            List<ClassInfo> classInfos = classInfoMapper.selectList(new QueryWrapper<ClassInfo>().lambda()
                    .eq(ClassInfo::getProductId, productIsSellDTO.getId())
                    .eq(ClassInfo::getClassStatus,"0"));
            if(classInfos.size()>0){
                throw new BusinessException("该商品已有拼班中班级，不允许下架");
            }
        }
        productMapper.updateById(product);
    }

    /**
     * 根据id删除商品
     *
     * @param idDTO
     */
    public void delete(IdDTO idDTO) {
        Boolean sell = productMapper.selectById(idDTO.getId()).getSell();
        if (sell) {
            throw new BusinessException("商品需下架后才可以删除");
        }
        productMapper.delete(new QueryWrapper<Product>().lambda()
                .eq(Product::getId, idDTO.getId())
                .eq(Product::getSell, false)
        );
    }

    /**
     * 根据校区和课程获取上架的商品
     *
     * @param courseId 课程id
     * @param campusId 校区id
     * @return List<Product>
     */
    public List<Product> getSellProduct(String courseId, String campusId) {
        List<String> productIds = this.productCampusRelMapper.selectIdsByCampusId(campusId);

        if (ParamUtils.isEmpty(productIds)) {
            return new ArrayList<>();
        }
        return this.list(new LambdaQueryWrapper<Product>()
                .eq(Product::getCourseId, courseId)
                .in(BaseEntity::getId, productIds)
                .eq(Product::getSell, true));
    }

    /**
     * 我要拼班
     *
     * @param dto dto
     * @return {@link MySpellClassVO}
     */
    public MySpellClassVO getMySpellClassList2(ProductCourseDetailsDTO dto) {

        MySpellClassVO mySpellClassVO = new MySpellClassVO();
        //根据商品Id查询商品信息
        Product product = this.getById(dto.getProductId());
        mySpellClassVO.setCoverImage(product.getCoverImage());
        mySpellClassVO.setProductId(product.getId());
        mySpellClassVO.setProductName(product.getProductName());
        mySpellClassVO.setOrganizationId(SecurityUtils.getOrganizationId());
        mySpellClassVO.setCampusId(dto.getCampusId());
        mySpellClassVO.setCourseId(product.getCourseId());
        //获取课表相关数据
        LambdaQueryWrapper<CourseSchedule> csWra = new LambdaQueryWrapper<>();
        csWra.eq(CourseSchedule::getDeleted, Boolean.FALSE);
        csWra.eq(CourseSchedule::getPublishStatus, Boolean.TRUE);
        csWra.eq(CourseSchedule::getCampusId, dto.getCampusId());
        csWra.eq(CourseSchedule::getCourseId, product.getCourseId());
        csWra.ge(CourseSchedule::getEndDate,new Date());
        List<CourseSchedule> courseScheduleList = courseScheduleMapper.selectList(csWra);
        List<String> kbIds = courseScheduleList.stream().map(CourseSchedule::getId).collect(Collectors.toList());
        //查询所有课表时段明细
        LambdaQueryWrapper<CourseScheduleDetail> csdWra = new LambdaQueryWrapper<>();
        // 1代办未拼班  5作废
        //csdWra.eq(CourseScheduleDetail::getStatus, ClassInfoStatusEnum.FINISH_CLASS.getValue()).or().eq(CourseScheduleDetail::getStatus,ClassInfoStatusEnum.DISSOLVE_CLASS_COLONEL.getValue());
        csdWra.eq(CourseScheduleDetail::getDeleted, Boolean.FALSE);
        List<CourseScheduleDetail> courseScheduleDetailList = courseScheduleDetailMapper.selectList(csdWra);
        //去重
        List<CourseScheduleDetail> scheduleDetailList = courseScheduleDetailList.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(o -> o.getScheduleId() + ";" + o.getStartTime() + ";" + o.getEndTime()))), ArrayList::new));
        //分组
        Map<String, List<CourseScheduleDetail>> csdMap = scheduleDetailList.stream().collect(Collectors.groupingBy(CourseScheduleDetail::getScheduleId));
        //查询课表时段明细关联教练表 数据
        LambdaQueryWrapper<CourseScheduleDetailCoachRel> csdcWrapper = new LambdaQueryWrapper<>();
        csdcWrapper.eq(CourseScheduleDetailCoachRel::getStatus, Boolean.TRUE);
        //csdcWrapper.eq(CourseScheduleDetailCoachRel::getScheduleDetailId,"8b8c0c7bd40eeb1d54206037e02b6c28");
        List<CourseScheduleDetailCoachRel> csdcList = scheduleDetailCoachRelMapper.selectList(csdcWrapper);
        //分组
        Map<String, List<CourseScheduleDetailCoachRel>> coachRelMap = csdcList.stream().collect(Collectors.groupingBy(CourseScheduleDetailCoachRel::getScheduleDetailId));
        //构造课表数据
        extractedScheduleData(mySpellClassVO, courseScheduleList, csdMap, coachRelMap);
        //根据商品Id查询拼班类型信息
        extractedSpellType(dto, mySpellClassVO);
        return mySpellClassVO;
    }

    public MySpellClassVO getMySpellClassList(ProductCourseDetailsDTO dto) {
        MySpellClassVO mySpellClassVO = new MySpellClassVO();
        //根据商品Id查询商品信息
        Product product = this.getById(dto.getProductId());
        if(ParamUtils.isEmpty(product)){
            throw new BusinessException("查无此商品");
        }
        mySpellClassVO.setCoverImage(product.getCoverImage());
        mySpellClassVO.setProductId(product.getId());
        mySpellClassVO.setProductName(product.getProductName());
        mySpellClassVO.setOrganizationId(SecurityUtils.getOrganizationId());
        mySpellClassVO.setCampusId(dto.getCampusId());
        mySpellClassVO.setCourseId(product.getCourseId());

        Date date = new Date();
        String nowDate = TimeUtils.toText(date,YYYY_MM_DD);
        //获取课表相关数据
        List<MyCourseScheduleVO> myCourseScheduleVOList = courseScheduleMapper.queryCourseScheduleList(dto.getCampusId(),product.getCourseId(),nowDate);
        //根据课表Id进行分组
        Map<String,List<MyCourseScheduleVO>> groupMap = myCourseScheduleVOList.stream().collect(Collectors.groupingBy(u->u.getScheduleId()));

        List<MyCourseScheduleVO> myCourseScheduleList = Lists.newArrayList();

        groupMap.forEach((item,list)->{

            MyCourseScheduleVO csVo = new MyCourseScheduleVO();
            csVo.setScheduleId(item);
            csVo.setScheduleName(list.get(0).getScheduleName());
            csVo.setCourseType(list.get(0).getCourseType());
            csVo.setWeekCode(list.get(0).getWeekCode());
            csVo.setStartDate(list.get(0).getStartDate());
            csVo.setEndDate(list.get(0).getEndDate());
            myCourseScheduleList.add(csVo);
            List<MyCourseScheduleVO> scheduleDetailList = list.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(
                MyCourseScheduleVO::getSectionCode))), ArrayList::new));
            List<PeriodVO> periodVoList = Lists.newArrayList();
            for (MyCourseScheduleVO myCourseScheduleVO : scheduleDetailList) {
                PeriodVO periodVO = new PeriodVO();
                if(ParamUtils.isNotEmpty(myCourseScheduleVO.getCoachRelId())){
                    periodVO.setStatus(NOT_PUT_GREY);
                }else{
                    //不可用
                    periodVO.setStatus(PUT_GREY);
                }
                periodVO.setStartTime(myCourseScheduleVO.getStartTime());
                periodVO.setEndTime(myCourseScheduleVO.getEndTime());
                periodVoList.add(periodVO);
            }
            csVo.setPeriodList(periodVoList);
        });

        //List<String> scheduleIds = myCourseScheduleVOList.stream().map(MyCourseScheduleVO::getScheduleId).collect(Collectors.toList());
        //List<String> sectionCodes = myCourseScheduleVOList.stream().map(MyCourseScheduleVO::getSectionCode).collect(Collectors.toList());
        //获取课表明细时段数据
        //List<MyCourseSchedulePeriodVO> myCourseSchedulePeriodVOList = courseScheduleDetailMapper.findCourseScheduleDetails(scheduleIds,sectionCodes);
        mySpellClassVO.setMyCourseScheduleList(myCourseScheduleList);
        //根据商品Id查询拼班类型信息
        extractedSpellType(dto, mySpellClassVO);
        return mySpellClassVO;

    }

    /**
     * 构造课表数据
     *
     * @param mySpellClassVO     我拼写类签证官
     * @param courseScheduleList 课程安排列表
     * @param csdMap             csd地图
     * @param coachRelMap        教练rel地图
     */
    private void extractedScheduleData(MySpellClassVO mySpellClassVO, List<CourseSchedule> courseScheduleList, Map<String, List<CourseScheduleDetail>> csdMap, Map<String, List<CourseScheduleDetailCoachRel>> coachRelMap) {
        List<MyCourseScheduleVO> myCourseScheduleList = new ArrayList<>();
        for (CourseSchedule courseSchedule : courseScheduleList) {

            MyCourseScheduleVO mcs = new MyCourseScheduleVO();
            mcs.setScheduleId(courseSchedule.getId());
            mcs.setScheduleName(courseSchedule.getScheduleName());
            mcs.setTotalNum(courseSchedule.getTotalNum());
            mcs.setCourseType(courseSchedule.getCourseType());
            mcs.setWeekCode(courseSchedule.getWeekCode());
            mcs.setStartDate(courseSchedule.getStartDate());
            mcs.setEndDate(courseSchedule.getEndDate());
            //获取课表时段明细表数据
            List<CourseScheduleDetail> csdList = csdMap.get(courseSchedule.getId());
            List<String> ids = csdList.stream().map(CourseScheduleDetail::getId).collect(Collectors.toList());
            if (ParamUtils.isNotEmpty(csdList)) {
                for (CourseScheduleDetail courseScheduleDetail : csdList) {
                    String startTime = TimeUtils.toText(courseScheduleDetail.getStartTime(),HH_MM);
                    String endTime = TimeUtils.toText(courseScheduleDetail.getEndTime(),HH_MM);
                    //根据课表Id和时段查询课表详情
                    List<CourseScheduleDetail> courseScheduleDetailList = courseScheduleDetailMapper.getCourseScheduleDetails(courseSchedule.getId(),startTime,endTime);
                    String status = courseScheduleDetail.getStatus();
                    for (CourseScheduleDetail scheduleDetail : courseScheduleDetailList) {

                        //只需要判断状态为1(未拼班)的数据,如果没有教练则设置为5(作废)
                        //if (Objects.equals(scheduleDetail.getStatus(), ScheduleDetailStatusEnum.UN_SPELL.getValue())) {
                            List<CourseScheduleDetailCoachRel> coachRelList = coachRelMap.get(scheduleDetail.getId());
                            //为空说明没有可用教练
                            if (ParamUtils.isEmpty(coachRelList)) {
                                //设置状态
                                courseScheduleDetail.setStatus("5");
                            }else{
                                courseScheduleDetail.setStatus(status);
                                break;
                            }
                        //}
                    }

                }
                mcs.setPeriodList(ParamUtils.isNotEmpty(BeanCopyUtil.copyListProperties(csdList, PeriodVO::new)) ? BeanCopyUtil.copyListProperties(csdList, PeriodVO::new) : Collections
                        .emptyList());
                myCourseScheduleList.add(mcs);
            }
        }
        mySpellClassVO.setMyCourseScheduleList(myCourseScheduleList);
    }

    /**
     * 根据商品Id查询拼班类型信息
     *
     * @param dto            dto
     * @param mySpellClassVO 我拼写类签证官
     */
    private void extractedSpellType(ProductCourseDetailsDTO dto, MySpellClassVO mySpellClassVO) {

        LambdaQueryWrapper<ProductCampusRel> pcWrap = new LambdaQueryWrapper<>();
        pcWrap.eq(ProductCampusRel::getProductId,dto.getProductId());
        pcWrap.eq(ProductCampusRel::getCampusId,dto.getCampusId());
        ProductCampusRel productCampusRel = productCampusRelMapper.selectOne(pcWrap);

        LambdaQueryWrapper<ProductSellPriceRel> psWra = new LambdaQueryWrapper<>();
        psWra.eq(ProductSellPriceRel::getProductId, dto.getProductId());
        psWra.eq(ProductSellPriceRel::getDeleted, Boolean.FALSE);
        psWra.eq(ProductSellPriceRel::getProductCampusId, productCampusRel.getId());
        List<ProductSellPriceRel> productSellPriceRelList = productSellPriceRelMapper.selectList(psWra);
        //查询出商品下--拼班类型对应的价格
        List<SpellClassPriceVO> spellClassPriceVOList = courseSellPriceRelMapper.findSpellClassPrice(dto.getProductId(),productCampusRel.getId());
        Map<String, SpellClassPriceVO> scpMap = spellClassPriceVOList.stream().collect(Collectors.toMap(SpellClassPriceVO::getCourseSellPriceRelId, scp -> scp));
        List<SpellTypeVO> spellTypeVoList = new ArrayList<>();
        for (ProductSellPriceRel productSellPriceRel : productSellPriceRelList) {
            SpellTypeVO vo = new SpellTypeVO();
            vo.setSpellType(productSellPriceRel.getTypeName());
            SpellClassPriceVO scp = scpMap.get(productSellPriceRel.getCourseSellPriceRelId());
            vo.setPrice(ParamUtils.isNotEmpty(scp) ? scp.getPrice() : BigDecimal.ZERO);
            vo.setProductSellPriceRelId(productSellPriceRel.getId());
            spellTypeVoList.add(vo);
        }
        mySpellClassVO.setSpellTypeList(spellTypeVoList);
    }

    /**
     * 小程序端-获取商品列表
     *
     * @return
     */
    public List<WxProductVO> getProduct() {
        List<WxProductVO> wxList = productMapper.findWxList();
        for (WxProductVO wxProductVO : wxList) {
            wxProductVO.setNum(ordersMapper.selectList(new QueryWrapper<Orders>()
                    .lambda()
                    .eq(Orders::getOrderStatus, "2")
                    .eq(Orders::getProductId, wxProductVO.getId())).size());
        }
        return wxList;
    }

    /**
     * @param productId 商品编号  不为空
     * @return
     */
    public String getDetails(String productId) {
        return productMapper.selectById(productId).getIntroduction();
    }

    /**
     * 商品评价
     *
     * @param productId 商品编号  不为空
     * @return
     */
    public List<WxEvaluateVO> getEvaluate(String productId) {
        return productMapper.evaList(productId);
    }

    /**
     * 获取课程表
     *
     * @param dto
     * @return
     */
    public List<CourseScheduleDetailVO> getProductCourse(OperationProductCourseDTO dto) {
        if(!dto.getCampusIds().isEmpty()){
            List<String> strings = Arrays.asList(dto.getCampusIds().split(";"));
            return courseScheduleService.schedulePreview(dto.getScheduleId(), strings,
                    dto.getCourseId(), dto.getStartTime(), dto.getEndTime(), null);
        }
        List<String> strings = new ArrayList<>();
        return courseScheduleService.schedulePreview(dto.getScheduleId(), strings,
                dto.getCourseId(), dto.getStartTime(), dto.getEndTime(), null);
    }

    /**
     * 获取课表id与名字列表
     *
     * @param courseId 校区id 不为空
     * @return
     */
    public List<CourseIdAndCourseNamelVO> getCourseId(String courseId) {

        List<CourseSchedule> courseSchedules = courseScheduleMapper.selectList(new QueryWrapper<CourseSchedule>().lambda()
                        .eq(!"0".equals(SecurityUtils.getOrganizationId()),CourseSchedule::getOrganizationId,SecurityUtils.getOrganizationId())
                .eq(CourseSchedule::getCourseId, courseId));
        return BeanCopyUtil.copyListProperties(courseSchedules, CourseIdAndCourseNamelVO::new);
    }

    /**
     * 获取课程id与名字列表（修改用）
     * @return
     */
    public List<GetCourseVO> getCourseByUpdate(String productId) {
        List<String> collect = productMapper.selectList(new QueryWrapper<Product>().lambda()
                        .eq(Product::getOrganizationId,SecurityUtils.getOrganizationId())
                        .ne(Product::getId,productId))
                .stream()
                .map(Product::getCourseId)
                .collect(Collectors.toList());
        if (collect.size() < 1) {
            List<Course> courses = courseMapper.selectList(null);
            return BeanCopyUtil.copyListProperties(courses, GetCourseVO::new);
        }
        List<Course> courses = courseMapper.selectList(new QueryWrapper<Course>().lambda().notIn(Course::getId, collect));
        return BeanCopyUtil.copyListProperties(courses, GetCourseVO::new);
    }
}
